# -*- coding: utf-8 -*-
"""
Author: chen xi
Date: 2025/4/30 上午11:27
File: ui_action.py
用途：用于处理用户操作，以及每个操作的实现
"""
import json
from pathlib import Path
from typing import Dict, Callable

from decorators.popup_handler import handle_popups
from src.com.logging_utils import Logger
from system_actions import SystemAction
from decorators.performance import timing_decorator
from decorators.retry_decorator import retry_decorator
from com.adb_commands import AdbManager as adb
from visual_test_suite.blackness_checker import is_black_screen
from com.screen_capture_utility import capture_element_screenshot
import time


class UIAction(SystemAction):
	def __init__(self, app_package_name=None, android_device_id=None):
		super().__init__(android_device_id, app_package_name)
		self.handlers: Dict[str, Callable] = {
			'空值': self.handle_empty,
			'填入内容': self.input_text,
			'点击按钮': self.click_ui_button,
			'单选按钮': self.click_radiobutton,
			'等待页面加载': self.wait_for_page_load,
			'坐标点击': self.click_button_by_coordinates,
			'可选操作': self.skip_uiaction,
			'连接热点': self.connect_ap,
			'滑动单选': self.swipe_and_tap,
			'滑动定位点击': self.scroll_to_element_and_click,
			'黑屏检测': self.check_screen_black,
			# '切换开关': self.toggleUiSwitch,
		}
	
	@handle_popups([
		('"ZWAP_IOTFAA-354431-WFBJT"不可上网，是否允许 WLAN 助理切换至更好的网络？', "不允许"),
		('"1234567890"网络质量差，是否允许 WLAN 助理切换至更好的网络？', "不允许"),
		("发现新版本啦", "暂不升级"),
		("权限请求", "允许"),
		("com.zwcode.p6slite:id/banner", "com.zwcode.p6slite:id/ic_close_cloud_free_dialog"),  # 直播页面云存储广告
	])  # 处理弹窗
	# @retry_decorator(max_retries=2, delay=5)
	def execute_action(self, _step, input_content=None):
		action_name = _step.get("控件类型")
		if action_name not in self.handlers:
			raise ValueError(f"Unsupported action: {action_name}")
		
		handler = self.handlers[action_name]
		return handler(_step, input_content)
	
	def handle_empty(self, **kwargs):
		"""处理空值情况"""
		print("Handling empty...")
	
	def input_text(self, *args):
		"""向指定元素输入文本"""
		usernameInput = self.find_element(args[0])
		# 清空输入框的当前内容
		usernameInput.set_text('')
		
		# 如果提供了内容，则发送内容到输入框
		usernameInput.send_keys(args[1])
		
		self.driver.press("enter")
	
	def click_ui_button(self, *args):
		"""模拟点击UI按钮"""
		button = self.find_element(args[0])
		button.click()
	
	def click_radiobutton(self, *args):
		"""模拟点击UI单选按钮"""
		if args[1] is None:
			return
		# 将锚点替换到元素中，然后滑动定位该元素
		args[0]["raw"]["text"] = args[1]
		button = self.find_element(args[0])
		button.click()
	
	@timing_decorator
	def wait_for_page_load(self, *args):
		"""
		等待页面加载完成的通用方法，包含多重超时检测机制

		参数:
			*args: 可变参数，第一个参数应为包含配置信息的字典，格式为:
				{
					"raw": {
						"out_time": int,  # 总超时时间(秒)，默认30
						...其他元素定位信息
					},
					"附加数据": str  # 可选的附加JSON数据
				}

		功能说明:
			1. 分阶段检测页面元素是否存在
			2. 第一阶段快速检测(5秒)是否进入加载状态
			3. 第二阶段检测加载状态是否消失(1/2总超时时间)
			4. 如有附加数据，第三阶段使用新配置重新检测
			5. 各阶段均有超时保护和日志记录
		"""
		# 获取总超时时间，默认30秒
		out_time = int(args[0].get("raw").get("out_time", 30))
		start_time = time.time()
		
		# 第一阶段：检查是否开始加载 (快速检测窗口5秒)
		Logger.info("开始页面加载状态检测流程")
		while not self.is_element_exists(args[0]):
			# Logger.info("检查页面是否正在加载")
			if time.time() - start_time > 5:
				Logger.info("未进入加载页面")
				break
		
		# 第二阶段：等待加载完成 (使用1/2总超时时间)
		while self.is_element_exists(args[0]):
			if time.time() - start_time > out_time // 2:
				Logger.info("加载超时")
				break
			time.sleep(0.5)  # 添加轮询间隔避免CPU过高
		
		# 第三阶段：处理附加数据配置
		if args[0].get("附加数据") == args[0].get("附加数据"):
			# 解析附加数据作为新配置
			args[0]["raw"] = json.loads(args[0].get("附加数据"))
			# Logger.info(f"使用附加数据配置，超时时间:{out_time}")
			
			# 最终检测阶段 (使用完整超时时间)
			while not self.is_element_exists(args[0]):
				if time.time() - start_time > out_time:
					Logger.info("最终加载超时")
					break
				time.sleep(1.0)  # 适当降低检查频率
			
			Logger.info("页面加载成功")
	
	def click_button_by_coordinates(self, *args):
		"""
		基于传入参数中的坐标点击按钮。

		:param args: 包含一个字典，字典中包含 "raw" 键，其值是一个包含 "bounds" 键的字典。
					 "bounds" 键的值是一个表示按钮边界的坐标字符串，格式为 "[x1,y1][x2,y2]"。
		"""
		try:
			# 获取坐标字符串
			coordinates_str = args[0].get("raw").get("bounds")
			
			# 调用 click_by_coordinates 方法进行点击
			self.click_by_coordinates(coordinates_str)
		except Exception as e:
			print(f"点击按钮失败: {e}")
			raise
	
	def skip_uiaction(self, *args):
		"""
		如果指定的UI元素存在，则执行点击操作；如果不存在，则直接返回不进行任何操作。

		参数:
		*args: 可变数量的位置参数。第一个参数预期为要检查的UI元素标识符，剩余的参数（如果有）将被传递给点击函数。
		"""
		# 检查传入的第一个参数所指代的UI元素是否存在于当前页面或上下文中。
		if self.is_element_exists(args[0]):
			# 若该元素存在，则调用self.click_ui_button方法，并传入所有参数来执行点击操作。
			# 注意：这里假设self.click_ui_button能够正确处理接收到的所有参数。
			self.click_ui_button(*args)
		else:
			# 若该UI元素不存在，则直接返回，不做任何进一步的操作。
			return
	
	def connect_ap(self, *args):
		"""
		连接指定的Wi-Fi网络（AP）。

		参数:
			*args: 可变参数，支持两种传参方式：
				1. 直接传入 (ssid, pwd) 元组，如 connect_ap(("MyWiFi", "123456"))
				2. 分别传入 ssid 和 pwd，如 connect_ap("MyWiFi", "123456")

		功能:
			- 检查参数类型，适配两种传参方式
			- 调用 adb 命令连接指定Wi-Fi网络
			- 要求 Android 设备已通过 adb 连接

		示例:
			# >>> connect_ap(("MyWiFi", "123456"))  # 方式1: 元组传参
		"""
		if isinstance(args[1], tuple):  # 检查第一个参数是否为元组（方式1）
			ssid = args[1][0]  # 从元组提取SSID（Wi-Fi名称）
			pwd = args[1][1]  # 从元组提取密码
			# 调用ADB命令连接Wi-Fi
			adb.connect_network(self.android_device_id, ssid, pwd)
	
	def swipe_and_tap(self, *args):
		"""模拟点击UI单选按钮"""
		if args[1] is None:
			return
		# 将锚点替换到元素中，然后滑动定位该元素
		args[0]["raw"]["text"] = args[1]
		self.find_element_by_swiping(args[0], args[1], max_attempts=40).click()
	
	def scroll_to_element_and_click(self, *args):
		"""模拟先拖动到锚点元素，然后定位元素位置，并点击"""
		if args[1] is None:
			return
		self.find_element_by_swiping(args[0], args[1], max_attempts=40).click()
	
	def check_screen_black(self, *args):
		"""
		检查给定元素是否显示黑屏。

		:param args: 元组，包含一个定位器参数，用于查找页面上的特定元素。
					 定位器可以是任何有效的 WebDriver 查找方式，如 By.ID、By.XPATH 等。
		:raises AssertionError: 如果检测到黑屏，则抛出断言错误。
		"""
		channel = 1
		Logger.info(f"args:{args}")
		if args[1] is not None:
			channel = args[1]
		Logger.info(f"channel:{channel}")
		for i in range(channel):
			# 使用传入的定位器查找页面上的元素
			element = self.find_element(args[0])[i]
			
			print(f"检测通道{i}是否黑屏")
			# 创建临时截图文件名，使用时间戳确保唯一性
			image_path = f"{self.project_root}/temp/element_screenshot_{int(time.time()*1000)}.png"
			
			# 确保保存截图的目录存在，如果不存在则创建
			Path(image_path).parent.mkdir(parents=True, exist_ok=True)
			
			# 对指定元素进行截图，并保存到上述生成的路径
			capture_element_screenshot(self.driver, element, image_path)
			
			# 断言该截图不是黑屏，如果是黑屏则抛出 AssertionError
			print(f"检测通道{i}{is_black_screen(image_path)}")
			assert not is_black_screen(image_path), "检测到黑屏！"


if __name__ == "__main__":
	import time
	
	step = {'页面名称': '首页', '相邻页面': '直播',
	        'raw': {'NAF': 'true', 'index': '1', 'text': '', 'resource-id': 'com.zwcode.p6slite:id/item_device_play',
	                'class': 'android.widget.ImageView', 'package': 'com.zwcode.p6slite', 'content-desc': '',
	                'checkable': 'false', 'checked': 'false', 'clickable': 'true', 'enabled': 'true',
	                'focusable': 'true', 'focused': 'false', 'scrollable': 'false', 'long-clickable': 'false',
	                'password': 'false', 'selected': 'false', 'visible-to-user': 'true', 'bounds': '[481,601][598,718]',
	                'drawing-order': '4', 'hint': '', 'display-id': '0'}, '控件类型': '单选按钮', '附加数据': None,
	        '等待时间': None}
	
	# 示例配置
	ANDROID_DEVICE_ID = "H675FIS8JJU8AMWW"  # 替换为实际设备ID
	APP_PACKAGE_NAME = "com.zwcode.p6slite"  # 替换为实际要启动的 App 包名
	
	# 创建驱动实例并启动 App
	android_app_driver = UIAction(APP_PACKAGE_NAME, ANDROID_DEVICE_ID)
	time.sleep(15)
	# android_app_driver.execute_action(_step=step)
	android_app_driver.connect_ap(("ZWAP_IOTFAA-680832-HSSLS", "01234567"))
